﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace NeturalMath.Expressions
{
    public class SimplifyingVisitor:MathExpressionVisitor<MathExpression>
    {

        public SimplifyingVisitor(MathRuntime runtime)
            :base(runtime)
        {
            
        }


        protected override MathExpression VisitAssignment(AssignmentExpression expression)
        {
            throw new NotImplementedException();
        }

        #region Operator Methods

        protected override MathExpression VisitBinaryOperator(BinaryOperatorExpression expression)
        {
            var left = Visit(expression.Left);
            var right = Visit(expression.Right);

            if (left is ConstantValueExpression && right is ConstantValueExpression)
            {
                return new ConstantValueExpression(expression.Execute(), Runtime);
            }

            switch (expression.OperatorType)
            {
                case BinaryOperatorType.Add:
                    return VisitAdd(left, right);
                case BinaryOperatorType.Subtract:
                    return VisitSubtract(left, right);
                case BinaryOperatorType.Multiply:
                    return VisitMultiply(left, right);
                case BinaryOperatorType.Divide:
                    return VisitDivide(left, right);
                case BinaryOperatorType.Modulo:
                    return VisitModulo(left, right);
                case BinaryOperatorType.Power:
                    return VisitPower(left, right);
                case BinaryOperatorType.And:
                    return VisitAnd(left, right);
                case BinaryOperatorType.Or:
                    return VisitOr(left, right);
                case BinaryOperatorType.Xor:
                    return VisitXor(left, right);
                case BinaryOperatorType.Equal:
                    return VisitEqual(left, right);
                case BinaryOperatorType.NotEqual:
                    return VisitNotEqual(left, right);
                case BinaryOperatorType.GreaterThan:
                    return VisitGreaterThan(left, right);
                case BinaryOperatorType.GreaterThanOrEqual:
                    return VisitGreaterThanOrEqual(left, right);
                case BinaryOperatorType.LessThan:
                    return VisitLessThan(left, right);
                case BinaryOperatorType.LessThanOrEqual:
                    return VisitLessThanOrEqual(left, right);
                case BinaryOperatorType.Range:
                    return VisitRange(left, right);
            }
            throw new NotImplementedException();
        }

        private MathExpression VisitRange(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitSubtract(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitMultiply(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitDivide(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitModulo(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitPower(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitAnd(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitOr(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitXor(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitEqual(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitNotEqual(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitGreaterThan(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitGreaterThanOrEqual(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitLessThan(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitLessThanOrEqual(MathExpression left, MathExpression right)
        {
            throw new NotImplementedException();
        }

        private MathExpression VisitAdd(MathExpression left, MathExpression right)
        {
            var leftConstant = left as ConstantValueExpression;
            var rightConstant = right as ConstantValueExpression;

            // check for zeros in addition and discard
            if ((leftConstant!=null) && (leftConstant.Value.Equals(Runtime.Zero)))
                return rightConstant;

            if ((rightConstant != null) && (rightConstant.Value.Equals(Runtime.Zero)))
                return leftConstant;

            // check for multiplication
            var multiplication = right as MultiplyOperation;
            if (multiplication !=null)
            {
                var constent = (multiplication.Left as ConstantValueExpression) ??
                               (multiplication.Right as ConstantValueExpression);

                var variable = (multiplication.Left as ConstantValueExpression) ??
                               (multiplication.Right as ConstantValueExpression);

                if (constent!=null)
                {
                    
                }
            }

            throw new NotImplementedException();
        }

        #endregion

        protected override MathExpression VisitConstant(ConstantValueExpression expression)
        {
            return expression;
        }


        protected override MathExpression VisitDomain(DomainExpression expression)
        {
            return expression;
        }

        protected override MathExpression VisitFunctionCall(FunctionUseExpression expression)
        {
            return expression;
        }

        protected override MathExpression VisitImportKeyword(ImportKeywordExpression expression)
        {
            return expression;
        }

        protected override MathExpression VisitMemberLookup(LookupExpression expression)
        {
            return expression;
        }

        protected override MathExpression VisitDefKeyword(DefKeywordExpression expression)
        {
            return expression;
        }

        protected override MathExpression VisitPrintKeyword(PrintKeywordExpression expression)
        {
            return expression;
        }

        protected override MathExpression VisitParameterExpression(FunctionParameterExpression expression)
        {
            throw new NotImplementedException();
        }

        protected override MathExpression VisitUnaryOperator(UnaryOperatorExpression expression)
        {
            throw new NotImplementedException();
        }

        protected override MathExpression VisitDelegate(DelegateExpression expression)
        {
            throw new NotImplementedException();
        }

        protected override MathExpression VisitSymbolicLookup(SymbolicLookupExpression expression)
        {
            throw new NotImplementedException();
        }
    }
}
